package video;

import java.io.File;

import org.gstreamer.Bus;
import org.gstreamer.ElementFactory;
import org.gstreamer.GstObject;
import org.gstreamer.State;
import org.gstreamer.TagList;
import org.gstreamer.Bus.ERROR;
import org.gstreamer.Bus.TAG;
import org.gstreamer.elements.PlayBin;

/**
 * Class that provide the metadata of a video file.
 * 
 * @version 0.3 December 01, 2009.
 * @author Heitor Meira de Melo.
 * 
 */
public class Metadata {
	private File file;
	private PlayBin playbin;
	private TagList tagList;
	private boolean isPlayable;
	private TAG tag;
	private ERROR error;

	/**
	 * Constructor of video Metadata.
	 * 
	 * @param file
	 *            A video file to get the metadata.
	 */
	public Metadata(String file) {
		setInputFile(new File(file));
	}

	/**
	 * Constructor of video Metadata.
	 * 
	 * @param file
	 *            A video file to get the metadata.
	 */
	public Metadata(File file) {
		setInputFile(file);
	}

	/**
	 * Connect the Bus of the playbin with the messenges.
	 */
	private void getMetadata() {

		tag = new Bus.TAG() {

			@Override
			public void tagsFound(GstObject arg0, TagList fileTags) {
				tagList = fileTags;
			}
		};

		error = new Bus.ERROR() {

			@Override
			public void errorMessage(GstObject arg0, int arg1, String arg2) {
				isPlayable = false;
				tagList = new TagList();
			}
		};

		/**
		 * Bus.TAG is called when when a new tag is identified on the stream.
		 */

		playbin.getBus().connect(tag);
		/**
		 * Bus.ERROR is called when an error happens in the playbin.
		 */
		playbin.getBus().connect(error);
	}

	/**
	 * Set the file to manipulate the metadata.
	 * 
	 * @param file
	 *            The file to manipulate.
	 */
	public void setInputFile(File file) {
		this.file = file;

		isPlayable = true;
		tagList = null;

		playbin = new PlayBin("Metadata: " + file);
		// A fakesink to disable the default window.
		playbin.setVideoSink(ElementFactory.make("fakesink", "videosink"));
		playbin.setInputFile(this.file);

		getMetadata();

		// TO get the metadata the video must be loaded in the (pipeline).
		playbin.setState(State.PAUSED);

		/*
		 * The getMetadata() has methods that run in a new Thread, a void while
		 * takes the Threads working in the right time.
		 */
		while (tagList == null) {
			;
		}
		getDuration();
		playbin.getBus().disconnect(tag);
		playbin.getBus().disconnect(error);
	}

	/**
	 * Provides the name of the video.
	 * 
	 * @return The name of the video.
	 */
	public String getVideoName() {
		return file.getName();
	}

	/**
	 * Provides the width of the video.
	 * 
	 * @return The width of the video, or null if this tag is not available.
	 */
	public String getWidth() {
		if (tagList.hasField("width")) {
			return tagList.getValues("width").get(0).toString();
		}
		return null;
	}

	/**
	 * Provides the heigth of the video.
	 * 
	 * @return The heigth of the video, or null if this tag is not available.
	 */
	public String getHeight() {
		if (tagList.hasField("height")) {
			return tagList.getValues("height").get(0).toString();
		}
		return null;
	}

	/**
	 * Provides the duration in seconds of the video.
	 * 
	 * @return The time duration, void string if this tag is not available.
	 */
	public double getDuration() {
		double duration = 0;
		try {
			if (tagList.hasField("totalduration")) {
				duration = Double.parseDouble(tagList
						.getValues("totalduration").get(0).toString());
			}
			duration = Integer.parseInt(tagList.getValues("duration").get(0)
					.toString());
		} catch (Exception ex) {
		}
		if (duration <= 0) {
			isPlayable = false;
		}
		return duration;
	}

	/**
	 * Provides the video container.
	 * 
	 * @return The container, or null if this tag is not available.
	 */
	public String getVideoContainer() {
		if (tagList.hasField("video-codec")) {
			return tagList.getValues("video-codec").get(0).toString();
		}
		return null;
	}

	/**
	 * Provides the audio container.
	 * 
	 * @return The container, or null if this tag is not available.
	 */
	public String getAudioContainer() {
		if (tagList.hasField("audio-codec")) {
			return tagList.getValues("audio-codec").get(0).toString();
		}
		return null;
	}

	/**
	 * Provides the path of the file.
	 * 
	 * @return The path of the file.
	 */
	public String getLocator() {
		return file.getAbsolutePath();
	}

	/**
	 * Provides the size in Bytes of the file.
	 * 
	 * @return The size of the file.
	 */
	public long getFileSize() {
		return file.length();

	}

	/**
	 * Provides the audio sample rate of the video.
	 * 
	 * @return The sample rate, or null if this tag is not available.
	 */
	public String getSampleRate() {
		if (tagList.hasField("audiosamplerate")) {
			return tagList.getValues("audiosamplerate").get(0).toString();
		}
		return null;
	}

	/**
	 * Provides the frame rate of the video.
	 * 
	 * @return The frame rate, or null if this tag is not available.
	 */
	public String getFrameRate() {
		if (tagList.hasField("framerate")) {
			return tagList.getValues("framerate").get(0).toString();
		}
		return null;
	}

	/**
	 * Ratings if the file is playable or not.
	 * 
	 * @return true, if the file is playable, false otherwise.
	 */
	public boolean isPlayable() {
		return isPlayable;
	}
}
